#include "gui_app_main.h"

/****************************
 *          宏定义          *
 ****************************/

#define APP_AXIS_WAVECHAR_WIDTH              900     /* 波形图标的宽度 */
#define APP_AXIS_WAVECHAR_HEIGHT             450     /* 波形图标的高度 */

#define APP_AXIS_WAVECHAR_X_POINT_NBR        50    /* Y轴数据线所具有的数据点个数 */
#define APP_AXIS_WAVECHAR_Y_POINT_NBR        50    /* Y轴数据线所具有的数据点个数 */

#define APP_AXIS_WAVECHAR_MAJOR_MINOR_SCALE  5    /* 大刻度线中间有几个小刻度线 */

#define APP_AXIS_X_RANGE_MIN                 0  /* X坐标的范围最小值 */
#define APP_AXIS_X_RANGE_MAX                 (APP_AXIS_WAVECHAR_Y_POINT_NBR / APP_AXIS_WAVECHAR_MAJOR_MINOR_SCALE)   /* X坐标的范围最大值 (这里x坐标是时间) */
#define APP_AXIS_Y_RANGE_MIN                 -32767      /* Y坐标的范围最小值 */
#define APP_AXIS_Y_RANGE_MAX                 32767       /* Y坐标的范围最大值 */

#define APP_AXIS_WAVE_MAX_NBR                9      /* 最大波形个数 */

#define APP_AXIS_COLOR_RED                   ((255 << 16) | (0 << 8) | (0 << 0)) /* 纯红色 */
#define APP_AXIS_COLOR_GREEN                 ((0 << 16) | (255 << 8) | (0 << 0)) /* 纯绿色 */
#define APP_AXIS_COLOR_BLUE                  ((0 << 16) | (0 << 8) | (255 << 0)) /* 纯蓝色 */
#define APP_AXIS_COLOR_WHITE                 ((255 << 16) | (255 << 8) | (255 << 0)) /* 纯红色 */

/* 将本APP的颜色数据转换为LVGL能识别的数值 */
#define APP_AXIS_2_LV_COLOR_R(x)             ((x & 0xFF0000) >> 16)
#define APP_AXIS_2_LV_COLOR_G(x)             ((x & 0x00FF00) >> 8)
#define APP_AXIS_2_LV_COLOR_B(x)             ((x & 0x0000FF) >> 0)

/****************************
 *       枚举和结构体        *
 ****************************/

/* 使能状态 */
enum
{
    APP_AXIS_WAVE_DISABLE = 0,  /* 不使能 */
    APP_AXIS_WAVE_ENABLE,       /* 使能 */
};

/* 菜单(功能)结构体 */
typedef struct APP_AXIS_WAVE
{
    uint8_t       status;            /* 状态 */
    const char    *text_en;          /* 文本 (英文) */
    const char    *text_cn;          /* 文本 (中文) */
    uint32_t      color;             /* 波形颜色 */
    int16_t       data[APP_AXIS_WAVECHAR_X_POINT_NBR];  /* 存储数据的buf */
} app_axis_wave_t;

/* 波形图表样式 */
typedef struct APP_AXIS_STYLE
{
    lv_style_t chart;      /* 背景样式 */
    lv_style_t wave;      /* 波形图表样式 */
    lv_style_t note_label[APP_AXIS_WAVE_MAX_NBR]; /* 波形注释样式 */
} app_axis_style_t;

/****************************
 *          全局变量        *
 ****************************/
static lv_obj_t *app_axis_root_obj = NULL;       /* 根父节点 */
static lv_obj_t *wave_char;
static lv_chart_series_t *wave_serial[APP_AXIS_WAVE_MAX_NBR];
static lv_obj_t *wave_label[APP_AXIS_WAVE_MAX_NBR];

static volatile uint8_t s_app_axis_status = GUI_APP_DESTROIED;  /* app的状态 */

/* 菜单功能项的特征 */
static const app_axis_wave_t s_app_axis_wave[APP_AXIS_WAVE_MAX_NBR] = 
{ 
    /*     使能状态         英文名    中文名字, 波形颜色(最好不相同) */
    {APP_AXIS_WAVE_ENABLE, "acc.x", NULL, APP_AXIS_COLOR_RED},
    {APP_AXIS_WAVE_ENABLE, "acc.y", NULL, APP_AXIS_COLOR_GREEN},
    {APP_AXIS_WAVE_ENABLE, "acc.z", NULL, APP_AXIS_COLOR_BLUE},
    {APP_AXIS_WAVE_DISABLE, "gyro.x", NULL, APP_AXIS_COLOR_RED},
    {APP_AXIS_WAVE_DISABLE, "gyro.y", NULL, APP_AXIS_COLOR_GREEN},
    {APP_AXIS_WAVE_DISABLE, "gyro.z", NULL, APP_AXIS_COLOR_BLUE},
    {APP_AXIS_WAVE_DISABLE, "mag.x", NULL},
    {APP_AXIS_WAVE_DISABLE, "mag.y", NULL},
    {APP_AXIS_WAVE_DISABLE, "mag.z", NULL}
};

/* 存储数据 */
static int16_t s_axis_data[APP_AXIS_WAVE_MAX_NBR][APP_AXIS_WAVECHAR_X_POINT_NBR] = {0};

/****************************
 *          辅助函数        *
 ****************************/


/****************************
 *      函数申明和实现       *
 ****************************/

/* 创建 label */
void s_app_axis_create_scope(lv_obj_t *parent)
{
    uint8_t                 i;
    uint16_t                y_offset = 0;
    static app_axis_style_t axis_style;
    static lv_style_t       label_cont_style;

    /* 初始化样式变量 */
    /* 图表背景样式 */
    lv_style_init(&axis_style.chart);
    lv_style_set_border_color(&axis_style.chart, lv_color_make(0xCC, 0xCC, 0xCC));    /* 边框的颜色 */
    lv_style_set_border_width(&axis_style.chart, 1);     /* 边框的宽度 */
    lv_style_set_border_opa(&axis_style.chart, LV_OPA_30);  /* 边框的透明度 */
    //lv_style_set_bg_color(&axis_style.chart,lv_color_make(39, 40, 34));    /* 设置图表的背景颜色 */
    lv_style_set_line_color(&axis_style.chart, lv_color_make(0xCC, 0xCC, 0xCC)); /* 分割线和刻度线的颜色 */
    lv_style_set_line_width(&axis_style.chart, 1);        /* 设置分割线和刻度线的宽度 */
    lv_style_set_line_opa(&axis_style.chart, LV_OPA_30);  /* 设置分割线透明度 */
    lv_style_set_text_color(&axis_style.chart, lv_color_make(0xA6, 0xe2, 0x2e));  /* 刻度线刻度的颜色 */
    lv_style_set_text_opa(&axis_style.chart, LV_OPA_50);  /* 设置文本透明度 */

    /* 波形样式 */
    lv_style_init(&axis_style.wave);
    lv_style_set_size(&axis_style.wave, 0); /* 数据行点不显示 */
    lv_style_set_line_opa(&axis_style.wave, LV_OPA_100);   /* 波形透明度 */
    lv_style_set_line_width(&axis_style.wave, 2);   /* 波形线宽 */

    /* 初始化装 note_label 的容器的风格 */
    lv_style_init(&label_cont_style);
    lv_style_set_bg_opa(&label_cont_style, LV_OPA_0);        /* 背景透明 */
    lv_style_set_border_opa(&label_cont_style, LV_OPA_0);    /* 边界透明度 */
    lv_style_set_pad_row(&label_cont_style, 10);   /* 水平两个label间间隔 */
    lv_style_set_layout(&label_cont_style, LV_LAYOUT_FLEX);              /* 布局方式弹性布局 */
    lv_style_set_flex_flow(&label_cont_style, LV_FLEX_FLOW_COLUMN);    /* 设置水平内容包裹flow风格 */

    /* 创建折线图表 */
    wave_char = lv_chart_create(parent);
    lv_obj_add_style(wave_char, &axis_style.chart, 0);       /* 设置图表的样式 */
    lv_obj_add_style(wave_char, &axis_style.wave, LV_PART_ITEMS); /* 设置波形的 线和条形 样式 */
    lv_obj_add_style(wave_char, &axis_style.wave, LV_PART_INDICATOR); /* 设置波形的 数据上的点的 样式 */
    lv_chart_set_type(wave_char, LV_CHART_TYPE_LINE);    /* 设置图表的线条类型-折线 */
    lv_obj_set_size(wave_char, APP_AXIS_WAVECHAR_WIDTH, APP_AXIS_WAVECHAR_HEIGHT); /* 设置图表的大小 */
    lv_obj_set_pos(wave_char, 50, 75);   /* 设置图表位置 */
    lv_obj_set_scrollbar_mode(wave_char, LV_SCROLLBAR_MODE_OFF);                /* 隐藏滚动条 */
    lv_chart_set_point_count(wave_char, APP_AXIS_WAVECHAR_Y_POINT_NBR); /* 设置每条数据线所具有的数据点个数 */
    lv_chart_set_range(wave_char, LV_CHART_AXIS_PRIMARY_X, APP_AXIS_X_RANGE_MIN, APP_AXIS_X_RANGE_MAX);  /* 设置x轴的数值范围 */
    lv_chart_set_range(wave_char, LV_CHART_AXIS_PRIMARY_Y, APP_AXIS_Y_RANGE_MIN, APP_AXIS_Y_RANGE_MAX);  /* 设置y轴的数值范围 */
    lv_chart_set_div_line_count(wave_char, (APP_AXIS_WAVECHAR_X_POINT_NBR / APP_AXIS_WAVECHAR_MAJOR_MINOR_SCALE) + 1, \
                                           (APP_AXIS_WAVECHAR_Y_POINT_NBR / APP_AXIS_WAVECHAR_MAJOR_MINOR_SCALE) + 1); /* <------- 设置水平和垂直分割线(刻度尺大格子个数) */
    lv_chart_set_update_mode(wave_char, LV_CHART_UPDATE_MODE_CIRCULAR);   /* 设置更新方式左移 */

    /* 
     * 添加x, y坐标轴的刻度线 
     *
     * L1: |         |         |         |         |         |         |
     * L2: | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
     * BS                                                           BE
     * 
     * major:
     * L1行从第一个'|'到最后一个'|'的像素点个数，即是： ?_tick_major_len
     * L1行的 '|' 之间间隔数就是：?_tick_major_cnt
     * 
     * minor:
     * L2行从第一个'|'到第 APP_AXIS_WAVECHAR_MAJOR_MINOR_SCALE 个'|'的像素点个数，即是： ?_tick_minor_len
     * L2行 APP_AXIS_WAVECHAR_MAJOR_MINOR_SCALE 即是 ?_tick_minor_cnt
     */

    lv_coord_t x_tick_major_len = APP_AXIS_WAVECHAR_WIDTH;             /* 即是图表x长度 */
    lv_coord_t x_tick_major_cnt = APP_AXIS_WAVECHAR_Y_POINT_NBR / APP_AXIS_WAVECHAR_MAJOR_MINOR_SCALE;    /* 大刻度 个数 */
    lv_coord_t x_tick_minor_len = APP_AXIS_WAVECHAR_WIDTH / APP_AXIS_WAVECHAR_Y_POINT_NBR; /* 图表x长度 / x轴上的点个数 就是一个小刻度的总长 */
    lv_coord_t x_tick_minor_cnt = APP_AXIS_WAVECHAR_MAJOR_MINOR_SCALE;        /* 小刻度数据个数 */
    lv_coord_t y_tick_major_len = APP_AXIS_WAVECHAR_HEIGHT;             /* 即是图表y长度 */
    lv_coord_t y_tick_major_cnt = APP_AXIS_WAVECHAR_X_POINT_NBR / APP_AXIS_WAVECHAR_MAJOR_MINOR_SCALE;    /* 大刻度 个数 */
    lv_coord_t y_tick_minor_len = APP_AXIS_WAVECHAR_HEIGHT / APP_AXIS_WAVECHAR_X_POINT_NBR; /* 图表y长度 / y轴上的点个数 就是一个小刻度的总长 */
    lv_coord_t y_tick_minor_cnt = APP_AXIS_WAVECHAR_MAJOR_MINOR_SCALE;        /* 小刻度数据个数 */

    lv_chart_set_axis_tick(wave_char, LV_CHART_AXIS_PRIMARY_X, x_tick_major_len, \
                                                               x_tick_minor_len, \
                                                               x_tick_major_cnt, \
                                                               x_tick_minor_cnt, \
                                                               true, 20);

    lv_chart_set_axis_tick(wave_char, LV_CHART_AXIS_PRIMARY_Y, y_tick_major_len, \
                                                               y_tick_minor_len, \
                                                               y_tick_major_cnt, \
                                                               y_tick_minor_cnt, \
                                                               true, 20);

    /* 创建一个容器, 用来放 note_label */
    lv_obj_t * label_cont = lv_obj_create(wave_char);
    lv_obj_set_size(label_cont, 100, 150);     /* 设置容器尺寸 */
    lv_obj_add_style(label_cont, &label_cont_style, 0);            /* 使用风格 */
    lv_obj_set_align(label_cont, LV_ALIGN_TOP_RIGHT);              /* 对齐方式, 左上角靠右 */
    lv_obj_set_scrollbar_mode(label_cont, LV_SCROLLBAR_MODE_OFF);                /* 隐藏滚动条 */

    /* 添加需要显示的数据波形线和对波形进行注释 */
    for (i = 0; i < APP_AXIS_WAVE_MAX_NBR; i++)
    {
        /* 判断波形是否使能 */
        if (s_app_axis_wave[i].status != APP_AXIS_WAVE_ENABLE)
        {
            continue;
        }

        /* 获得用户设置的color */
        lv_color_t serial_color = lv_color_make(APP_AXIS_2_LV_COLOR_R(s_app_axis_wave[i].color), \
                                                APP_AXIS_2_LV_COLOR_G(s_app_axis_wave[i].color), \
                                                APP_AXIS_2_LV_COLOR_B(s_app_axis_wave[i].color));

        /* 添加一条数据线(指定曲线颜色) */
        wave_serial[i] = lv_chart_add_series(wave_char, serial_color, LV_CHART_AXIS_PRIMARY_Y);

        /* 在图标右上角对波形进行注释 */
        wave_label[i] = lv_label_create(label_cont);
        lv_label_set_text(wave_label[i], s_app_axis_wave[i].text_en);     /* 设置label文本 */

        /* 初始化注释label的样式 */
        lv_style_init(&axis_style.note_label[i]);
        lv_style_set_text_color(&axis_style.note_label[i], serial_color);
        lv_obj_add_style(wave_label[i], &axis_style.note_label[i], 0);
    }

    return;
}

/* 周期性刷新波形 */
void gui_app_axis_update_data(void)
{
    dt_3axis_s2 axis_data[3] = {0};
    uint16_t    i, j = 0;
    int16_t     *pdata;

    /* 判断app的运行状态 */
    if (s_app_axis_status != GUI_APP_CREATED)
    {
        return; /* app未被执行, 返回 */
    }

    /* 获得AXIS数据 (暂时只读GYRO, 因为懒) */
    if (gui_hw_axis_ctrl(DEV_MPU9250_DATA_ACC, &axis_data[DEV_MPU9250_DATA_ACC]) != RET_OK)
    {
        return;  /* 读取失败 */
    }

    /* 指向读取到的数据 */
    pdata = (int16_t *) &axis_data;

    /* 存储数据 */
    for (i = 0; i < APP_AXIS_WAVE_MAX_NBR; i++)
    {
        /* 判断波形是否使能 */
        if (s_app_axis_wave[i].status != APP_AXIS_WAVE_ENABLE)
        {
            continue;
        }

        /* 滑动移去老数据 */
        for (j = 0; j < (APP_AXIS_WAVECHAR_X_POINT_NBR - 1); j++)
        {
            s_axis_data[i][j] = s_axis_data[i][j + 1];
        }

        /* 添加新数据 */
        s_axis_data[i][j] = pdata[i];
    }
    
    /* 设置折线图点数据 */
    for (i = 0; i < APP_AXIS_WAVE_MAX_NBR; i++)
    {
        /* 判断波形是否使能 */
        if (s_app_axis_wave[i].status != APP_AXIS_WAVE_ENABLE)
        {
            continue;
        }
        
        /* 设置数据 */
        lv_chart_set_ext_y_array(wave_char, wave_serial[i], (lv_coord_t*) &s_axis_data[i]);
    }

    /* 刷新操作 */
    lv_chart_refresh(app_axis_root_obj);

    return;
}

/* 设置app的状态 */
void gui_app_axis_status_ctrl(uint8_t status)
{
    s_app_axis_status = status;

    return;
}

/* 创建这个项目 */
lv_obj_t * gui_app_axis_create(lv_obj_t *parent, void *user_data)
{
    /* 应用初始化 */
    lv_obj_t *axis_obj = gui_app_common_init(parent, "app_axis", gui_app_axis_status_ctrl);

    /* 记录该应用最基本的对象 */
    app_axis_root_obj = axis_obj;

    /* 创建折线图表 */
    s_app_axis_create_scope(app_axis_root_obj);

    /* 返回该对象 */
    return axis_obj;
}
